package pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.strategies;

/**
 * 
 * @author Jarek Fuks, Zbigniew Nazimek
 *
 * Simple greedy strategy. Stops after when_stop failed steps.
 *
 */



import pl.wroc.uni.ii.evolution.engine.EvPopulation;
import pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.bayesnetwork.EvIBayesianNetwork;
import pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.metrics.EvIMetric;
import pl.wroc.uni.ii.evolution.engine.operators.spacespecific.binaryvector.boa.utils.EvBinary;
import pl.wroc.uni.ii.evolution.engine.prototype.EvIndividual;
import pl.wroc.uni.ii.evolution.utils.EvRandomizer;

public class EvGreedyStrategy<T extends EvIndividual> implements EvIStrategy<T> {

  int stop;
   
  /**
   * 
   * @param when_stop, number of tries to improve network
   */
  public EvGreedyStrategy(int when_stop) {
    stop = when_stop;
  }
  
  public EvIBayesianNetwork<T> evaluate(EvPopulation<T> population, EvIBayesianNetwork<T> network, EvIMetric<T> metric) {
    EvBinary ev_binary = new EvBinary();
    double current_metric = metric.compute(population, network, ev_binary);
    double new_metric = 0.0;
    boolean changed = true;
    EvIBayesianNetwork<T> new_network = network;
    
    while (changed) {
      changed = false;
      for (int i = 0; i < stop; i++) {
        new_network = randomChange(network);
        new_metric = metric.compute(population, new_network, ev_binary);
        
        if (new_metric > current_metric) {
          current_metric = new_metric;
          changed = true;
          network = new_network;
          break;
        }
      }
    }
    return new_network;
  }
  
  protected EvIBayesianNetwork<T> randomChange(EvIBayesianNetwork<T> network_param) {
    EvIBayesianNetwork<T> network = network_param.clone();
    int from = EvRandomizer.INSTANCE.nextInt(network.getSize());
    int to = EvRandomizer.INSTANCE.nextInt(network.getSize());
    while(!(network.addEdge(from, to) || network.removeEdge(from, to))) {
      from = EvRandomizer.INSTANCE.nextInt(network.getSize());
      to = EvRandomizer.INSTANCE.nextInt(network.getSize());
    }
    return network;
  }

}
